package com.apes.scm.pur.purchaseReturn.model;

import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.framework.plugin.soe.annotations.State;
import com.apes.framework.plugin.soe.annotations.States;
import com.apes.framework.util.ApesConst;
import com.apes.framework.util.Arith;
import com.apes.framework.util.LogicalUtil;
import com.apes.scm.account.account.model.Cooperation;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.stock.transfer.model.Pick;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

/**
 *返厂单
 */
@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = PurchaseReturn.CONST_TABLE_NAME,indexes = {
        @Index(name = "idx_return_supplier_id", columnList = "supplier_id")
})
public class PurchaseReturn extends Model {
    public static final String CONST_TABLE_NAME = "pur_purchase_return";

    /*
    * prefix 前缀 规则以 % 隔开 (yy) 代表年份
    * */
    @Id
    @Column(name = "id", length = 32)
    @ApesGenerator(code = CONST_TABLE_NAME, name = "返厂订单", prefix = "FC%(company)%(yy)%(month)", padding = 4, useDateRange=true)
    @Comment("返厂订单编码")
    private String id;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", referencedColumnName = "id")
    @Comment("公司")
    private PartyRole company; //公司

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id", referencedColumnName = "id", nullable = false)
    @Comment("部门")
    private Dept dept; //部门

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "clerk_id", referencedColumnName = "id", updatable = false)
    @Comment("业务员")
    private PartyRole clerk; //业务员

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pick_id", referencedColumnName = "id")
    @Comment("交货单")
    private Pick pick;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "location_id", referencedColumnName = "id")
    @Comment("仓库库区")
    private Location location;  //库存位置

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "contract_id", referencedColumnName = "id")
    @Comment("合同号")
    private Contract contract; //合同号

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "supplier_id", referencedColumnName = "id", nullable = false)
    @Comment("供应商")
    private PartyRole supplier; //供应商

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cooperation_id", referencedColumnName = "id")
    @Comment("合作方式")
    private Cooperation cooperation; //合作方式

//    @Column(name = "move_type", length = 10)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "move_type", referencedColumnName = "id")
    @Comment("交货方式（direct：部分交货，one：一次性交货）")
    private Enumeration moveType; //交货方式：("direct", "部分交货"), ("one", "一次性交货");


    @Column(name = "amt_tax", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("税金")
    private double amtTax = 0; //税金

    @Column(name = "amt_untaxed", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("不含税金额")
    private double amtUntaxed = 0; //不含税金额

    @Column(name = "amt_total", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("总计")
    private double amtTotal = 0; //总计

    @Column(name = "supplier_ref", length = 30)
    @Comment("供应商参考")
    private String supplierRef;    //供应商参考

    @Column (name ="note")
    @Comment("备注")
    private String note;  // 备注

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "approve_uid", referencedColumnName = "id")
    @Comment("审批人")
    private PartyRole approveUid; //创建人

    @Column(name = "date_approve")
    @Comment("审批日期")
    private Date dateApprove; //审批日期

    @Column(name = "date_order")
    @Comment("单据日期")
    private Date dateOrder; //单据日期

    @Column(name = "date_planned")
    @Comment("计划日期")
    private Date datePlanned; //计划日期

    @Column(name = "date_cancel")
    @Comment("取消日期")
    private Date dateCancel; //取消日期

    @Comment("取消人")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cancel_uid", referencedColumnName = "id")
    private PartyRole cancelUId;//终止

    @Column(name = "is_shipped")
    @Comment("已送货")
    private boolean shipped = false; //已送货

    @Column(name = "invoice_status", length = 10)
    @Comment("账单状态（no：没有开票，to_invoice：开票中，invoicedComplete：开票完成）")
    private String invoiceStatus = "no"; //账单状态: ("no", "没有开票"), ("to_invoice", "开票中"), ("invoicedComplete", "开票完成")

    @Column(name = "state", length = 32, nullable = false)
    @States(name = "订单状态", values = {
            @State(id = "sent", name = "新建"),
            @State(id = "apply", name = "申请"),
            @State(id = "approve", name = "审核"),
            @State(id = "financeApprove", name = "财务审核"),
            @State(id = "done", name = "已完成"),
            @State(id="delete", name = "删除"),
            @State(id = "cancel", name = "已取消")})
    private String state; //状态： ('sent', '返厂申请'), ('approve', '返厂订单'), ('done', '已完成'), ('cancel', '已取消')

    @Column(name = "origin", length = 30)
    @Comment("源单据")
    private String origin;

    @Column(name = "origin_business_type", length = 32)
    @Comment("源单据类型")
    private String originBusinessType;

    @Comment("自动交货")
    @Column(name = "auto", columnDefinition = ApesConst.FIELD_BOOLEAN_FALSE)
    private boolean auto = false;
    // mappedBy标签是定义在被拥有方的，他指向拥有方 （只有OneToOne,OneToMany,ManyToMany上才有mappedBy属性，ManyToOne不存在该属性）
    // mappedBy这方定义的JoinColumn/JoinTable总是失效的，不会建立对应的字段或者表
    // optional=true 表示不能没有明细表
    // orphanRemoval = true 表示主表删除，明细表关联数据一起删除
    @OneToMany(mappedBy = "purchaseReturn", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<PurchaseReturnItem> purchaseReturnItems  = new HashSet();

    public Set<PurchaseReturnItem> getPurchaseReturnItems() {
        for(PurchaseReturnItem item: purchaseReturnItems) {
            item.setPurchaseReturn(this);
        }
        return purchaseReturnItems;
    }


    public void computeAmt() {
        double newAmtTotal = 0, newAmtUntaxed = 0, newAmtTax = 0;
        for (PurchaseReturnItem item : purchaseReturnItems) {
            item.computeAmt();
            newAmtUntaxed += item.getPriceSubtotal();
            newAmtTax += item.getPriceTax();
        }
        amtUntaxed = newAmtUntaxed;
        amtTax = newAmtTax;
        amtTotal = newAmtUntaxed + newAmtTax;

    }


    /**
     *  获取服务商品
     */
    @Transient
    public List<PurchaseReturnItem> queryServiceProduct() {
        return this.getPurchaseReturnItems().stream()
                .filter(
                        item -> LogicalUtil.in(item.getProduct().getType(),"aut")
                ).collect(Collectors.toList());
    }

    /**
     *  获取未发货服务商品
     */
    public List<PurchaseReturnItem> queryPhysicalProduct() {
        return this.getPurchaseReturnItems().stream()
                .filter(
                        item -> item.getProductReturnQty() != item.getQtyReceived()
                                && LogicalUtil.notIn(item.getProduct().getType(),"aut")
                ).collect(Collectors.toList());
    }

    /**
     * 功能：设置订单交货状态
     */
    public void setShipped() {
        // 存在不为服务商品并且发货数量不等于返厂数量， 说明还有未发货
        long result = queryPhysicalProduct().size();
        if(result == 0) {
            this.setShipped(true);
            this.setState();
        }
    }


    /**
     * 功能：设置订单完成状态
     */
    public void setState() {
        if (!state.equals("approve")) return;
        setState("done");
    }
    public double compute() {
        return purchaseReturnItems.stream().map(PurchaseReturnItem::getPriceTotal).reduce(Arith::add).orElse(0.0);
    }
}
